package array

import (
	"errors"
	"fmt"
	"strings"
)

type tCustomArray struct {
	items []interface{}
	size int
}

var gIndexOutofBoundsError = errors.New("index out of bounds")

func NewArray() IArray {
	return &tCustomArray{
		items: make([]interface{}, 0),
		size: 0,
	}
}

func (me *tCustomArray) Size() int {
	return me.size
}

func (me *tCustomArray) IsEmpty() bool {
	return me.size <= 0
}

func (me *tCustomArray) IsNotEmpty() bool {
	return !me.IsEmpty()
}

func (me *tCustomArray) Get(i int) (error,interface{}) {
	if i >= me.size || i < 0 {
		return gIndexOutofBoundsError, nil
	}
	return nil, me.items[i]
}

func (me *tCustomArray) Set(i int, it interface{}) error {
	if i >= me.size || i < 0 {
		return gIndexOutofBoundsError
	}
	me.items[i] = it
	return nil
}

func (me *tCustomArray) Append(it interface{}) {
	me.items = append(me.items, it)
	me.size++
}

func (me *tCustomArray) Remove(i int) error {
	if i >= me.size || i < 0 {
		return gIndexOutofBoundsError
	}

	me.items = append(me.items[:i], me.items[i+1:]...)
	me.size--

	return nil
}


func (me *tCustomArray) Insert(i int, it interface{}) error {
	if i > me.size || i < 0 {
		return gIndexOutofBoundsError
	}

	newItems := make([]interface{}, 0)
	newItems = append(newItems, me.items[:i]...)
	newItems = append(newItems, it)
	newItems = append(newItems, me.items[i:]...)

	me.items = newItems
	me.size++
	return nil
}


func (me *tCustomArray) Iterator() IArrayIterator {
	return newArrayIterator(me.items)
}

func (me *tCustomArray) String() string {
	ss := make([]string, me.size)
	for i,it := range me.items {
		ss[i] = fmt.Sprintf("%v", it)
	}
	return fmt.Sprintf("[%s]", strings.Join(ss, ","))
}
